#
# Copyright 2008 Qumranet, Inc. All rights reserved.
# Use is subject to license terms.
#
import storage_exception
from time import time
from glob import glob
import os
import sp
import sd
import volume

class Metabackend:
    def __init__(self, storage_dir, log):
        self.log = log
        self.storage_repository = storage_dir

    def isVolumeExist(self, sdUUID, spUUID, imgUUID, uuid):
        """Check whether the Volume 'uuid' is present in the repository
        """
        raise Exception("shouldn't be here")
        file = self.getVolumeMetaFile(sdUUID, spUUID, imgUUID, uuid)
        volPath = file[:-len('.meta')]
        return os.path.exists(volPath)

    def addNewVolume(self, sdUUID, spUUID, imgUUID, uuid, size, volPath, volType, preallocate):
        """Add a new Volume 'uuid' of size 'size' to the repository
        """
        raise Exception("shouldn't be here")
        metadata = ["TYPE=%s\n" % volType, "SIZE=%u\n" % size, "CTIME=%u\n" % int(time()),
                    sd.POOL+"=%s\n" % spUUID, "DOMAIN=%s\n" % sdUUID, "IMAGE=%s\n" % imgUUID,
                    "DESCRIPTION=\n", "PUUID=%s\n" % volume.BLANK_UUID]
        file = volPath + ".meta"
        self.setMetadata(file, metadata)
#        f = open(file, "w")
#        f.writelines(metadata)
#        f.close()

    def addNewChild(self, sdUUID, spUUID, imgUUID, uuid, puuid, volPath, volType, preallocate):
        """Create a new child 'uuid' for parent 'puuid'
        """
        raise Exception("shouldn't be here")
        if self.isVolumeExist(sdUUID, spUUID, imgUUID, puuid):
            psize = self.getVolumeInfo(sdUUID, spUUID, imgUUID, puuid)['size']
            metadata = ["FORMAT=%s\n" % volType, "TYPE=%s\n" % preallocate,
                        "SIZE=%u\n" % psize, "CTIME=%u\n" % int(time()),
                        sd.POOL+"=%s\n" % spUUID, "DOMAIN=%s\n" % sdUUID,
                        "IMAGE=%s\n" % imgUUID,
                        "DESCRIPTION=\n", "PUUID=%s\n" % puuid]
            file = volPath + ".meta"
            self.setMetadata(file, metadata)
#            f = open(file, "w")
#            f.writelines(metadata)
#            f.close()
        else:
            raise storage_exception.VolumeDoesNotExist(puuid)

    def removeVolume(self, sdUUID, spUUID, imgUUID, uuid):
        """Remove the Volume 'uuid' from the repository
        """
        raise Exception("shouldn't be here")
        if self.isVolumeExist(sdUUID, spUUID, imgUUID, uuid):
            file = self.getVolumeMetaFile(sdUUID, spUUID, imgUUID, uuid)
            os.unlink(file)
        else:
            raise storage_exception.VolumeDoesNotExist(uuid)

    def getAllVolumes(self, sdUUID, spUUID, imgUUID):
        """Fetch the list of the Volumes UUIDs
        """
        # Get Volumes of whole pool
        raise Exception("shouldn't be here")
        pattern = os.path.join(self.storage_repository, spUUID, sdUUID, sd.DOMAIN_IMAGES)
        if imgUUID and imgUUID != volume.BLANK_UUID:
            # Get Volumes of particular image
            pattern = os.path.join(pattern, imgUUID, '*.meta')
        else:
            pattern = os.path.join(pattern, '*', '*.meta')
        files = glob(pattern)
        volList = []
        for i in files:
            if os.path.splitext(os.path.basename(i))[0] not in os.path.dirname(i):
                volList.append(os.path.splitext(os.path.basename(i))[0])
        return volList

    def getVolumePath(self, sdUUID, spUUID, imgUUID, uuid):
        """Return a path of Volume 'uuid'
        """
        raise Exception("shouldn't be here")
        file = self.getVolumeMetaFile(sdUUID, spUUID, imgUUID, uuid)
        volPath = file[:-len('.meta')]
        if not os.path.exists(volPath):
            raise storage_exception.VolumeDoesNotExist(uuid)
        else:
            return volPath

    def getVolumeInfo(self, sdUUID, spUUID, imgUUID, uuid):
        """Return a dictionary containing the information on Volume 'uuid'
        """
        raise Exception("shouldn't be here")
        file = self.getVolumeMetaFile(sdUUID, spUUID, imgUUID, uuid)
        # We need to collect the following info
        # uuid (we have it already)
        # path (calculate it)
        # size, parent, description, ctime, legality (all five from .meta)
        # children list (derive from the other .meta files)
        if not self.isVolumeExist(sdUUID, spUUID, imgUUID, uuid):
            raise storage_exception.VolumeDoesNotExist(uuid)
        # Parse metadata
        metadata = self.getMetadata(file)

#        metadata = open(file).read().splitlines()
        legality = 'LEGAL'
        size = 0
        puuid = descr = ctime = volType = volFormat = pool = dom = img = ""
        for i in metadata:
            if i.find("=") < 0:
                continue
            (param, value) = i.split("=")
            if param == "SIZE":
                size = value.strip()
            elif param == "FORMAT":
                volFormat = value.strip()
            elif param == "TYPE":
                volType = value.strip()
            elif param == "PUUID":
                puuid = value.strip()
            elif param == "DESCRIPTION":
                descr = value.strip()
            elif param == sd.POOL:
                pool = value.strip()
            elif param == "DOMAIN":
                dom = value.strip()
            elif param == "IMAGE":
                img = value.strip()
            elif param == "CTIME":
                ctime = value.strip()
            elif param == "LEGALITY":
                legality = value.strip()
            else:
                self.log.error('Unkown param %s (value %s)' % (param, value))

        info = {'uuid': uuid, 'type': volType, 'format':volFormat, 'size': int(size), 'parent': puuid,
                'description': descr, 'pool': pool, 'domain': dom, 'image': img,
                'ctime': ctime, 'legality': legality }
        # Now collect children info
        cpattern = "%s/*.meta" % os.path.dirname(file)
        files = glob(cpattern)
        children = []
        for i in files:
            if "PUUID=%s" % uuid in self.getMetadata(i):
                # Match found. extract that Volume id and record it
                children.append(os.path.splitext(os.path.basename(i))[0])
        info['children'] = children
        return info

    def isVolumeBusy(self, spUUID, uuid):
	"""Checks whether the Volume is busy being copied from/to
	"""
        raise Exception("shouldn't be here")
        busy = False
        pattern = os.path.join(self.storage_repository, spUUID, sp.POOL_TASKS, '*')
        tasks = glob(pattern)
        lock = None
        for i in tasks:
            descriptor = self.getMetadata(i)
#            descriptor = open(i).read().splitlines()
            for item in descriptor:
                if "LOCK=" in item:
                    lock = item.split("=")[1]
            if lock is not None and uuid in lock:
                busy = True
        return busy

    def setVolumeDescr(self, sdUUID, spUUID, imgUUID, uuid, descr):
        """Set new description 'descr' for the Volume 'uuid'
        """
        raise Exception("shouldn't be here")
        self.setMetaParam(sdUUID, spUUID, imgUUID, uuid, "DESCRIPTION", descr)

    def setVolumeLegality(self, sdUUID, spUUID, imgUUID, uuid, legality):
	"""Set new legality for the Volume 'uuid'
	"""
        raise Exception("shouldn't be here")
        self.setMetaParam(sdUUID, spUUID, imgUUID, uuid, "LEGALITY", legality)

    def getVolumeMetaFile(self, sdUUID, spUUID, imgUUID, uuid):
        """Finds the Volume .meta file and performs trivial validation
        """
        raise Exception("shouldn't be here")
        if imgUUID == volume.BLANK_UUID:
            img = '*'
        else:
            img = imgUUID
        METAPATTERN = os.path.join(self.storage_repository, spUUID, sdUUID,
            sd.DOMAIN_IMAGES, img, uuid+'.meta')
        file = glob(METAPATTERN)
        if len(file) == 0:
            raise storage_exception.VolumeDoesNotExist(uuid)
        return file[0]

    def setMetaParam(self, sdUUID, spUUID, imgUUID, uuid, key, value):
        raise Exception("shouldn't be here")
        file = self.getVolumeMetaFile(sdUUID, spUUID, imgUUID, uuid)
        metadata = self.getMetadata(file)
#        metadata = open(file).readlines()
        new_metadata = []
        new_param = True
        for i in metadata:
            if key not in i:
                new_metadata.append(i)
            else:
                new_param = False
                param = key + "=%s\n" % value
                new_metadata.append(param)
        # Add new parameter
        if new_param:
            param = key + "=%s\n" % value
            new_metadata.append(param)
        self.setMetadata(file, new_metadata)
#        f = open(file + ".new", "w")
#        f.writelines(new_metadata)
#        f.close()
#        os.rename(file + ".new", file)

    def getMetaParam(self, sdUUID, spUUID, imgUUID, uuid, key):
        raise Exception("shouldn't be here")
        file = self.getVolumeMetaFile(sdUUID, spUUID, imgUUID, uuid)
        metadata = self.getMetadata(file)
#        metadata = open(file).readlines()
        for i in metadata:
            if key in i:
                value = i.split('=')[1].strip()
                break
            else:
                value = ''
        return value

    def setMetadata(self, file, metadata):
        raise Exception("shouldn't be here")
        # First workaround for block-based metadata
        open(file, "w").writelines(" " * 512)
        f = open(file, "w")
        f.writelines(metadata)
        f.write("\nEOF\n")
        f.close()

    def getMetadata(self, file):
        raise Exception("shouldn't be here")
        f = open(file)
        out = []
        for l in f:
            if l.startswith("EOF"):
                self.log.error('file= %s (out= %s)' % (file, str(out)))
                return out
            out.append(l)
        return out
